/*
 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.oa.poa;

import org.omg.PortableServer.Servant;

import org.omg.PortableServer.POAPackage.WrongPolicy;
import org.omg.PortableServer.POAPackage.ServantNotActive;
import org.omg.PortableServer.POAPackage.ServantAlreadyActive;
import org.omg.PortableServer.POAPackage.ObjectNotActive;
import org.omg.PortableServer.POAPackage.ObjectAlreadyActive;

import com.sun.corba.se.impl.orbutil.concurrent.SyncUtil;

import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.orbutil.ORBConstants;

import com.sun.corba.se.impl.javax.rmi.CORBA.Util;

import com.sun.corba.se.impl.oa.NullServantImpl;

public abstract class POAPolicyMediatorBase_R extends POAPolicyMediatorBase {
    protected ActiveObjectMap activeObjectMap;

    POAPolicyMediatorBase_R(Policies policies, POAImpl poa) {
        super(policies, poa);

        // assert policies.retainServants() && policies.useActiveObjectMapOnly()
        if (!policies.retainServants())
            throw poa.invocationWrapper().policyMediatorBadPolicyInFactory();

        activeObjectMap = ActiveObjectMap.create(poa, !isUnique);
    }

    public void returnServant() {
        // NO-OP
    }

    public void clearAOM() {
        activeObjectMap.clear();
        activeObjectMap = null;
    }

    protected Servant internalKeyToServant(ActiveObjectMap.Key key) {
        AOMEntry entry = activeObjectMap.get(key);
        if (entry == null)
            return null;

        return activeObjectMap.getServant(entry);
    }

    protected Servant internalIdToServant(byte[] id) {
        ActiveObjectMap.Key key = new ActiveObjectMap.Key(id);
        return internalKeyToServant(key);
    }

    protected void activateServant(ActiveObjectMap.Key key, AOMEntry entry, Servant servant) {
        setDelegate(servant, key.id);

        if (orb.shutdownDebugFlag) {
            System.out.println("Activating object " + servant +
                    " with POA " + poa);
        }

        activeObjectMap.putServant(servant, entry);

        if (Util.isInstanceDefined()) {
            POAManagerImpl pm = (POAManagerImpl) poa.the_POAManager();
            POAFactory factory = pm.getFactory();
            factory.registerPOAForServant(poa, servant);
        }
    }

    public final void activateObject(byte[] id, Servant servant)
            throws WrongPolicy, ServantAlreadyActive, ObjectAlreadyActive {
        if (isUnique && activeObjectMap.contains(servant))
            throw new ServantAlreadyActive();
        ActiveObjectMap.Key key = new ActiveObjectMap.Key(id);

        AOMEntry entry = activeObjectMap.get(key);

        // Check for an ObjectAlreadyActive error
        entry.activateObject();
        activateServant(key, entry, servant);
    }

    public Servant deactivateObject(byte[] id)
            throws ObjectNotActive, WrongPolicy {
        ActiveObjectMap.Key key = new ActiveObjectMap.Key(id);
        return deactivateObject(key);
    }

    protected void deactivateHelper(ActiveObjectMap.Key key, AOMEntry entry,
                                    Servant s) throws ObjectNotActive, WrongPolicy {
        // Default does nothing, but the USE_SERVANT_MANAGER case
        // must handle etherealization

        activeObjectMap.remove(key);

        if (Util.isInstanceDefined()) {
            POAManagerImpl pm = (POAManagerImpl) poa.the_POAManager();
            POAFactory factory = pm.getFactory();
            factory.unregisterPOAForServant(poa, s);
        }
    }

    public Servant deactivateObject(ActiveObjectMap.Key key)
            throws ObjectNotActive, WrongPolicy {
        if (orb.poaDebugFlag) {
            ORBUtility.dprint(this,
                    "Calling deactivateObject for key " + key);
        }

        try {
            AOMEntry entry = activeObjectMap.get(key);
            if (entry == null)
                throw new ObjectNotActive();

            Servant s = activeObjectMap.getServant(entry);
            if (s == null)
                throw new ObjectNotActive();

            if (orb.poaDebugFlag) {
                System.out.println("Deactivating object " + s + " with POA " + poa);
            }

            deactivateHelper(key, entry, s);

            return s;
        } finally {
            if (orb.poaDebugFlag) {
                ORBUtility.dprint(this,
                        "Exiting deactivateObject");
            }
        }
    }

    public byte[] servantToId(Servant servant) throws ServantNotActive, WrongPolicy {
        // XXX needs to handle call from an invocation on this POA

        if (!isUnique && !isImplicit)
            throw new WrongPolicy();

        if (isUnique) {
            ActiveObjectMap.Key key = activeObjectMap.getKey(servant);
            if (key != null)
                return key.id;
        }

        // assert !isUnique || (servant not in activateObjectMap)

        if (isImplicit)
            try {
                byte[] id = newSystemId();
                activateObject(id, servant);
                return id;
            } catch (ObjectAlreadyActive oaa) {
                // This can't occur here, since id is always brand new.
                throw poa.invocationWrapper().servantToIdOaa(oaa);
            } catch (ServantAlreadyActive s) {
                throw poa.invocationWrapper().servantToIdSaa(s);
            } catch (WrongPolicy w) {
                throw poa.invocationWrapper().servantToIdWp(w);
            }

        throw new ServantNotActive();
    }
}
